﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Drawing.Text;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using hxc.COM;
using hxc.Win32;
using Microsoft.Win32;

namespace hxc
{
	public class CBrowserButton : Button
	{
		public CBrowserButton() : base()
		{
			this.SetStyle(ControlStyles.EnableNotifyMessage, true);
			this.Paint += new PaintEventHandler(Btn_Paint);
			this.MouseDown += new MouseEventHandler(Btn_MouseDown);
			this.MouseUp += new MouseEventHandler(Btn_MouseUp);
			this.MouseEnter += new EventHandler(Btn_MouseEnter);
			this.MouseLeave += new EventHandler(Btn_MouseLeave);
            m_imgDisable = new Bitmap(@"..\File_SyncUI\pic\BrowserButton_Disable.png");
            m_imgHover = new Bitmap(@"..\File_SyncUI\pic\BrowserButton_Hover.png");
            m_imgNormal = new Bitmap(@"..\File_SyncUI\pic\BrowserButton_Normal.png");
            m_imgSelected = new Bitmap(@"..\File_SyncUI\pic\BrowserButton_Click.png");
			m_imgNow = m_imgNormal;
		}

		//DataMember
		private Image m_imgNormal;
		private Image m_imgHover;
		private Image m_imgSelected;
		private Image m_imgDisable;
		private Image m_imgNow;
		private ushort m_ArrowAngle;
		public ushort ArrowAngle
		{
			get
			{
				return m_ArrowAngle;
			}
			set
			{
				m_ArrowAngle = value;
				this.Refresh();
			}
		}

		//OverrideFunction

		//EventHandler
		private void Btn_Paint(object sender, PaintEventArgs pevent)
		{
			Graphics g = pevent.Graphics;
			g.FillRectangle(new SolidBrush(this.BackColor), this.ClientRectangle);
			PointF TheRotationPoint = new PointF(this.Bounds.X + this.Bounds.Width / 2, this.Bounds.Y + this.Bounds.Height / 2);	//rotation   point 
			g.TranslateTransform(TheRotationPoint.X, TheRotationPoint.Y);
			g.RotateTransform(m_ArrowAngle);
			g.TranslateTransform(-TheRotationPoint.X, -TheRotationPoint.Y);
			g.SmoothingMode = SmoothingMode.HighQuality;

			if (this.Enabled)
				g.DrawImage(m_imgNow, this.ClientRectangle, new Rectangle(0, 0, m_imgNow.Width, m_imgNow.Height), GraphicsUnit.Pixel);
			else
				g.DrawImage(m_imgDisable, this.ClientRectangle, new Rectangle(0, 0, m_imgNow.Width, m_imgNow.Height), GraphicsUnit.Pixel);

			g.ResetTransform();
		}

		private void Btn_MouseDown(object sender, MouseEventArgs e)
		{
			if (e.Button == MouseButtons.Left)
			{
				m_imgNow = m_imgSelected;
				this.Refresh();
			}
		}

		private void Btn_MouseUp(object sender, MouseEventArgs e)
		{
			m_imgNow = m_imgHover;
			this.Refresh();
		}

		private void Btn_MouseEnter(object sender, EventArgs e)
		{
			m_imgNow = m_imgHover;
			this.Refresh();
		}

		private void Btn_MouseLeave(object sender, EventArgs e)
		{
			m_imgNow = m_imgNormal;
			this.Refresh();
		}
	}

	public class CTBButton : Button
	{
		protected enum Btn_Status
		{
			BS_LButtonDown,
			BS_RButtonDown,
			BS_MouseEnter,
			BS_Normal
		}

		public CTBButton(ContextMenuStrip Menu)
		{
			if (Menu != null)
			{
				m_Menu = Menu;
				m_Menu.Closing += new ToolStripDropDownClosingEventHandler(Btn_MenuDestroy);
			}
			this.MouseDown += new MouseEventHandler(Btn_MouseDown);
			this.MouseUp += new MouseEventHandler(Btn_MouseUp);
			this.MouseEnter += new EventHandler(Btn_MouseEnter);
			this.MouseLeave += new EventHandler(Btn_MouseLeave);
			this.MouseMove += new MouseEventHandler(Btn_MouseMove);
			this.Paint += new PaintEventHandler(Btn_Paint);
			BkgundColorH_Normal = Color.FromArgb(253, 254, 255);
			BkgundColorL_Normal = Color.FromArgb(221, 233, 247);
			BkgundColorH_Click = Color.FromArgb(248, 251, 254);
			BkgundColorL_Click = Color.FromArgb(193, 210, 232);
			BkgundColorH_Hover = Color.FromArgb(253, 254, 255);
			BkgundColorL_Hover = Color.FromArgb(221, 233, 247);
			BorderColor_Outside = Color.FromArgb(182, 199, 218);
			BorderColor_Inside = Color.FromArgb(255, 255, 255);
		}

		//DataMember
		protected Btn_Status m_Status = Btn_Status.BS_Normal;
		protected ContextMenuStrip m_Menu;
		public readonly Color BkgundColorH_Normal;
		public readonly Color BkgundColorL_Normal;
		public readonly Color BkgundColorH_Hover;
		public readonly Color BkgundColorL_Hover;
		public readonly Color BkgundColorH_Click;
		public readonly Color BkgundColorL_Click;
		public readonly Color BorderColor_Outside;
		public readonly Color BorderColor_Inside;
 
		//EventHandler
		private void Btn_Paint(object s, PaintEventArgs e)
		{
			Graphics g = e.Graphics;
			Rectangle rcClient = this.ClientRectangle;
			DrawBkgund(g, rcClient);
            rcClient.Width -= 1;
            rcClient.Height -= 1;
			DrawBorder(g, rcClient);
			DrawSurface(g, rcClient);
		}
		
		private void Btn_MouseDown(object sender, MouseEventArgs e)
		{
			if (e.Button == MouseButtons.Left)
			{
				m_Status = Btn_Status.BS_LButtonDown;
				Point ptMenu = new Point(this.Left - 5, this.Bottom - 5);
				m_Menu.Show(this.PointToScreen(ptMenu));
				this.Refresh();
			}
		}

		private void Btn_MouseUp(object sender, MouseEventArgs e)
		{
			if (!m_Menu.Visible) 
				m_Status = Btn_Status.BS_Normal;
			this.Refresh();
		}

		private void Btn_MouseEnter(object sender, EventArgs e)
		{
			m_Status = Btn_Status.BS_MouseEnter;
			this.Refresh();
		}

		private void Btn_MouseLeave(object sender, EventArgs e)
		{
			if (!m_Menu.Visible) 
				m_Status = Btn_Status.BS_Normal;
			this.Refresh();
		}

		private void Btn_MouseMove(object s, MouseEventArgs e)
		{
			
		}

		private void Btn_MenuDestroy(object s, ToolStripDropDownClosingEventArgs e)
		{
			m_Status = Btn_Status.BS_Normal;
			this.Refresh();
		}

		protected void DrawBkgund(Graphics g, Rectangle rcClient)
		{
			Point CenterTop = new Point(rcClient.X + rcClient.Width / 2, rcClient.Y);
			Point CenterBottom = new Point(CenterTop.X, rcClient.Bottom);
			LinearGradientBrush lgb = null;
			switch (m_Status)
			{
				case Btn_Status.BS_LButtonDown:
					{
						//float[][] cm = {
						//                  new float[5]{0.8F, 0F, 0F, 0F, 0F},
						//                  new float[5]{0F, 0.8F, 0F, 0F, 0F},
						//                  new float[5]{0F, 0F, 0.8F, 0F, 0F},
						//                  new float[5]{0F, 0F, 0F, 1F, 0F},
						//                  new float[5]{0F, 0F, 0F, 0F, 1F}
						//              };
						//float[] colorm = new float[5]{BkgundColorL.R, BkgundColorL.G, BkgundColorL.B, BkgundColorL.A, 1};
						lgb = new LinearGradientBrush(CenterTop, CenterBottom, BkgundColorH_Click, BkgundColorL_Click);
					}
					break;
				case Btn_Status.BS_MouseEnter:
					{
						lgb = new LinearGradientBrush(CenterTop, CenterBottom, BkgundColorH_Hover, BkgundColorL_Hover);
					}
					break;
				case Btn_Status.BS_Normal:
					{
						lgb = new LinearGradientBrush(CenterTop, CenterBottom, BkgundColorH_Normal, BkgundColorL_Normal);
					}
					break;
			}
			g.FillRectangle(lgb, rcClient);
		}

		protected void DrawBorder(Graphics g, Rectangle rcClient)
		{
			if (m_Status == Btn_Status.BS_MouseEnter)
			{
				GraphicsPath RoundRect = GdiPlus.CreateRoundRect(rcClient.X, rcClient.Y, rcClient.Width, rcClient.Height, 4);
				g.DrawPath(new Pen(BorderColor_Outside), RoundRect);
				RoundRect = GdiPlus.CreateRoundRect(rcClient.X + 1, rcClient.Y + 1, rcClient.Width - 2, rcClient.Height - 2, 3);
				g.DrawPath(new Pen(BorderColor_Inside), RoundRect);
			}
			if (m_Status == Btn_Status.BS_LButtonDown)
			{
				GraphicsPath RoundRect = GdiPlus.CreateRoundRect(rcClient.X, rcClient.Y, rcClient.Width, rcClient.Height, 4);
				g.DrawPath(new Pen(BorderColor_Outside), RoundRect);
			}
		}

		protected void DrawSurface(Graphics g, Rectangle rcClient)
		{
			g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
			GraphicsPath pathText = new GraphicsPath();
			pathText.AddString(this.Text, this.Font.FontFamily, (int)FontStyle.Regular, this.Font.Size, new Point(0, 0), new StringFormat(StringFormatFlags.LineLimit));
			RectangleF rc = pathText.GetBounds();
			rc.X = rcClient.X + (rcClient.Width - rc.Width) / 3.5F;
			rc.Y = rcClient.Y + (rcClient.Height - rc.Height) / 4F;
			PointF[] Zeniths = new PointF[3];
			Zeniths[0] = new PointF(rc.Right + 13, rc.Top + 7);
			Zeniths[1] = new PointF(Zeniths[0].X + 8, Zeniths[0].Y);
			Zeniths[2] = new PointF(Zeniths[0].X + 4F, Zeniths[0].Y + 4);
			g.DrawString(this.Text, this.Font, new SolidBrush(Color.Black), rc.Location);
			GraphicsPath pathTriangle = new GraphicsPath();
			pathTriangle.AddLines(Zeniths);
			g.FillPath(new SolidBrush(Color.Black), pathTriangle);
		}
	}

	public class CBrowserTB : Form
	{
		public CBrowserTB(Form Parent, Point pt, int Height)
		{
			this.components = new System.ComponentModel.Container();
			User32.SetParent(this.Handle, Parent.Handle);
			User32.WndStyle dwStyle = User32.WndStyle.WS_CHILD | User32.WndStyle.WS_VISIBLE | User32.WndStyle.WS_CLIPCHILDREN |
										User32.WndStyle.WS_CLIPSIBLINGS;
			User32.SetWindowLong(this.Handle, User32.GWL_Param.GWL_STYLE, dwStyle);
			this.Location = pt;
			m_Parent = Parent;
			this.Height = Height;
            this.Width = Parent.Width;
			Parent.Resize += new EventHandler(AutoReSize);
			this.Paint += new PaintEventHandler(TB_Paint);
			this.SuspendLayout();
			this.Show(Parent);
			BkgundColorL = Color.FromArgb(221, 233, 247);
			BkgundColorH = Color.FromArgb(253, 254, 255);
		}

		protected override void Dispose(bool disposing)
		{
			if (disposing && (components != null))
			{
				components.Dispose();
			}
			base.Dispose(disposing);
		}

		//DataMember
		private Form m_Parent;
		private System.ComponentModel.IContainer components = null;
		public readonly Color BkgundColorH;
		public readonly Color BkgundColorL;
		
		//MemberFunction
		public Button InsertButton(string Caption, string Name, int BtnWidth, ContextMenuStrip PopupMenu)
		{
			CTBButton Neighbour = null;
			if (this.Controls.Count > 0)
				Neighbour = (CTBButton)this.Controls[this.Controls.Count - 1];
			CTBButton newButton = new CTBButton(PopupMenu);
			newButton.Name = Name;
			newButton.Text = Caption;
			newButton.Width = BtnWidth;
			newButton.Height = this.Height - 12;
			newButton.Top = 6;
			if (Neighbour != null)
				newButton.Left = Neighbour.Right + 5;
			else
				newButton.Left = 5;
			this.Controls.Add(newButton);
			newButton.Font = this.Font;
			return newButton;
		}

		public Button GetButton(string Name)
		{
			return (Button)this.Controls[Name];
		}

		//EventHandler
		private void TB_Paint(object s, PaintEventArgs e)
		{
			Graphics g = e.Graphics;
			Rectangle rc = this.ClientRectangle;
			rc.Width -= 4;
			rc.Height -= 1;
			Point CenterTop = new Point(rc.X + rc.Width / 2, rc.Y);
			Point CenterBottom = new Point(CenterTop.X, rc.Bottom);
			LinearGradientBrush lgb = new LinearGradientBrush(CenterTop, CenterBottom, BkgundColorH, BkgundColorL);
			g.FillRectangle(lgb, this.ClientRectangle);
		}

		private void AutoReSize(object s, EventArgs e)
		{
			Form Parent = (Form)s;
			this.Width = Parent.Width;
		}
	}

    public class FileSystemView : ListView
    {
        public FileSystemView(Form Parent, string Path)
        {
            Parent.Controls.Add(this);

            //添加系统ImageList
            Shell32.SHGetImageList(Shell32.SHImageListType.SHIL_SMALL, ref IID.IID_IImageList, out SmallIconList);
            Shell32.SHGetImageList(Shell32.SHImageListType.SHIL_EXTRALARGE, ref IID.IID_IImageList, out NormalIconList);
            //User32.SendMessage(this.Handle, User32.LVM_SETIMAGELIST, (IntPtr)User32.LVSIL_SMALL, pSmallIconList);
            //User32.SendMessage(this.Handle, User32.LVM_SETIMAGELIST, (IntPtr)User32.LVSIL_NORMAL, pNormalIconList);

            this.Thumbnails = new ImageList();
            this.Thumbnails.ImageSize = new Size(128, 128);
            this.Thumbnails.ColorDepth = ColorDepth.Depth32Bit;
            this.SmallImageList = new ImageList();
            this.SmallImageList.ImageSize = new Size(32, 32);
            this.SmallImageList.ColorDepth = ColorDepth.Depth32Bit;
            this.LargeImageList = new ImageList();
            this.LargeImageList.ImageSize = new Size(48, 48);
            this.LargeImageList.ColorDepth = ColorDepth.Depth32Bit;
            if (Path[Path.Length - 1] != '\\')
                Path += '\\';
            CurrentPath = Path;

            this.OwnerDraw = true;
            this.DoubleBuffered = true;
            this.DrawItem += ListView_OnDrawItem;
            this.DrawSubItem += ListView_OnDrawSubItem;
            this.DrawColumnHeader += ListView_OnDrawColumnHeader;
        }

        public ImageList Thumbnails;
        public comctl32.IImageList NormalIconList;
        public comctl32.IImageList SmallIconList;

        private string _CurrentPath;
        public string CurrentPath
        {
            get
            {
                return _CurrentPath;
            }
            set
            {
                _CurrentPath = value;
                RefreshFile();
            }
        }

        protected void RefreshFile()
        {
            /*DirectoryInfo DirInfo = new DirectoryInfo(_CurrentPath);
            IEnumerable<FileSystemInfo> Entries = DirInfo.EnumerateFileSystemInfos();
            foreach (FileSystemInfo fsi in Entries)
            {
                ListViewItem LVItem = new ListViewItem(fsi.Name);
                Shell32.SHFILEINFOW sfi = new Shell32.SHFILEINFOW();
                Kernel32.File_Attribute Attr = ((fsi.Attributes & FileAttributes.Directory) == FileAttributes.Directory) ?
                                Kernel32.File_Attribute.FILE_ATTRIBUTE_DIRECTORY : Kernel32.File_Attribute.FILE_ATTRIBUTE_NORMAL;
                Shell32.SHGetFileInfo(fsi.FullName, Attr, ref sfi, Marshal.SizeOf(sfi),
                                    Shell32.SHGFI.SHGFI_SYSICONINDEX | Shell32.SHGFI.SHGFI_USEFILEATTRIBUTES);
                LVItem.ImageIndex = sfi.iIcon;
                this.Items.Add(LVItem);
            }*/
            Thumbnails.Images.Clear();

            IntPtr pidl = Shell32.ILCreateFromPath(_CurrentPath);
            if (pidl == IntPtr.Zero)
                throw new ArgumentException("Can't find path \"" + _CurrentPath + "\"");
            IntPtr ppv, pildLast;
            ShlObj.IShellFolder2 isf2 = (ShlObj.IShellFolder2)Shell32.SHGetDesktopFolder();
            isf2.BindToObject(pidl, IntPtr.Zero, ref IID.IID_IShellFolder, out ppv);
            isf2 = (ShlObj.IShellFolder2)Marshal.GetObjectForIUnknown(ppv);
            Marshal.Release(ppv);
            ShlObj.IEnumIDList eid = null;
            isf2.EnumObjects(IntPtr.Zero, ShlObj.SHCONTF.SHCONTF_FOLDERS | ShlObj.SHCONTF.SHCONTF_NONFOLDERS, out eid);
            Marshal.FreeCoTaskMem(pidl);
            int hr = 0;
            while (true)
            {
                hr = eid.Next(1, out pidl, out pildLast);
                if ((hr < 0) || (hr == 1))
                    break;
                StringBuilder sb = new StringBuilder(260);
                Shell32.SHGetPathFromIDList(pidl, sb);
                if ((sb.ToString() != _CurrentPath) && (sb.Length != 0))//剔除当前目录本身
                {
                    string Path = _CurrentPath;
                    Path += System.IO.Path.GetFileName(sb.ToString());
                    ListViewItem LVItem = new ListViewItem(System.IO.Path.GetFileName(Path));
                    if (!Shlwapi.PathIsDirectory(Path))
                    {
                        IntPtr[] idl = { Shell32.ILFindLastID(pidl) };
                        if (isf2.GetUIObjectOf(IntPtr.Zero, 1, idl, ref IID.IID_IExtractImage, 0, out ppv) >= 0)
                        {
                            ShlObj.IExtractImage iei = (ShlObj.IExtractImage)Marshal.GetObjectForIUnknown(ppv);
                            Marshal.Release(ppv);
                            StringBuilder sbIEI = new StringBuilder(260);
                            int dwPriority = 0;
                            int dwFlags = (int)ShlObj.IExtractImageFlags.Screen;
                            GDI32.SIZE ImgSize = new GDI32.SIZE(128, 128);
                            iei.GetLocation(sbIEI, 260, ref dwPriority, ref ImgSize, 32, ref dwFlags);
                            IntPtr hBitMap = IntPtr.Zero;
                            iei.Extract(out hBitMap);
                            Image img = Image.FromHbitmap(hBitMap);
                            this.Thumbnails.Images.Add(System.IO.Path.GetFileName(sb.ToString()), img);
                            Win32.GDI32.DeleteObject(hBitMap);
                        }
                        Shell32.SHFILEINFO sfi = new Shell32.SHFILEINFO();
                        Shell32.SHGetFileInfo(Path, 0, ref sfi, Marshal.SizeOf(sfi), Shell32.SHGFI.SHGFI_SYSICONINDEX);
                        LVItem.ImageIndex = sfi.iIcon;
                    }
                    else
                    {
                        Shell32.SHFILEINFO sfi = new Shell32.SHFILEINFO();
                        Shell32.SHGetFileInfo("DIRECTORY", Kernel32.File_Attribute.FILE_ATTRIBUTE_DIRECTORY, ref sfi,
                            Marshal.SizeOf(sfi), Shell32.SHGFI.SHGFI_SYSICONINDEX | Shell32.SHGFI.SHGFI_USEFILEATTRIBUTES);
                        LVItem.ImageIndex = sfi.iIcon;
                    }
                    this.Items.Add(LVItem);
                }
                Marshal.FreeCoTaskMem(pidl);
            }
        }

        protected virtual void ListView_OnDrawItem(Object sender, DrawListViewItemEventArgs e)
        {
            //e.DrawDefault = false;
            e.Graphics.DrawRectangle(new Pen(Color.FromArgb(255, 0, 0), 2), e.Bounds);
            IntPtr hIcon;
            Shell32.SHFILEINFO sfi = new Shell32.SHFILEINFO();
            Shell32.SHGetFileInfo(_CurrentPath + e.Item.Text, 0, ref sfi, Marshal.SizeOf(sfi), Shell32.SHGFI.SHGFI_SYSICONINDEX);
            NormalIconList.GetIcon(sfi.iIcon, comctl32.IMAGELISTDRAWPARAMSFlag.ILD_NORMAL, out hIcon);
            Icon ico = (Icon)Icon.FromHandle(hIcon).Clone();
            User32.DestroyIcon(hIcon);
            e.Graphics.DrawIcon(ico, e.Bounds);
        }

        protected virtual void ListView_OnDrawSubItem(Object sender, DrawListViewSubItemEventArgs e)
        {
            e.DrawDefault = true;
        }

        protected virtual void ListView_OnDrawColumnHeader(Object sender, DrawListViewColumnHeaderEventArgs e)
        {

        }
    }
}